package com.knowledge.plus.深拷贝和浅拷贝;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 引用拷贝：
 * 将一个对象的引用赋值给另一个变量，两个变量实际上指向同一个对象。修改其中一个变量会影响另一个变量
 * -
 * 浅拷贝 ：
 * 浅拷贝会在堆上创建一个新的对象（区别于引用拷贝的一点），
 * 不过，如果原对象内部的属性是引用类型的话，浅拷贝会直接复制内部对象的引用地址，也就是说拷贝对象和原对象共用同一个内部对象。
 * -
 * 深拷贝 ：
 * 深拷贝会完全复制整个对象，包括这个对象所包含的内部对象。
 *
 * @author TPF
 * @since 2024/3/11
 */
public class CloneableDemo {

    public static void main(String[] args) {
        Person person1 = new Person("张珊", new Address("浙江省", "杭州市"));
        Person person2 = person1.clone();
        // 引用拷贝/浅拷贝 时，输出为：false
        // 深拷贝 时，输出为：true
        System.out.println(person1.getAddress() == person2.getAddress());
    }

}

/**
 * 人员类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
class Person implements Cloneable {
    /* 姓名 */
    private String name;
    /* 地址 */
    private Address address;

    /**
     * 实现 Cloneable 接口并重写 clone 方法来实现
     */
    @Override
    public Person clone() {
        try {
            return (Person) super.clone();  // 浅拷贝，复制内部对象的引用地址，共用同一个对象（即：内部address为引用拷贝）
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
    // @Override
    // public Person clone() {
    //     try {
    //         Person clone = (Person) super.clone();
    //         if (address != null) {
    //             clone.address = address.clone();    // 深拷贝地址对象
    //         }
    //         return clone;
    //     } catch (CloneNotSupportedException e) {
    //         throw new AssertionError();
    //     }
    // }

}

/**
 * 地址类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
class Address implements Cloneable {

    /* 省 */
    private String province;
    /* 市 */
    private String city;

    @Override
    public Address clone() {
        try {
            return (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

}
